package cn.ilikes.tools.hbase.jpa.clients;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.hadoop.hbase.client.Result;
import org.slf4j.Logger;

import cn.ilikes.tools.hbase.jpa.JPAHbasePersistenUnitEnv;
import cn.ilikes.tools.hbase.jpa.JPAHbaseSystemEnv;
import cn.ilikes.tools.hbase.jpa.SysConfigs;
import cn.ilikes.tools.hbase.jpa.clients.datahander.DataHander;
import cn.ilikes.tools.hbase.jpa.clients.nodes.Node;
import cn.ilikes.tools.hbase.jpa.clients.nodes.NodeLifeCycle.LifeCycle;
import cn.ilikes.tools.hbase.jpa.indexs.IndexClient;
import cn.ilikes.tools.hbase.jpa.metadatas.IEntityMetaData;
import cn.ilikes.tools.hbase.jpa.metadatas.elements.EntityFields;
import cn.ilikes.tools.hbase.jpa.metadatas.elements.JPAField;
import cn.ilikes.tools.hbase.jpa.metadatas.elements.Relation;
import cn.ilikes.tools.hbase.jpa.metadatas.elements.Relation.ForeignKey;
import cn.ilikes.tools.hbase.jpa.proxys.LazyInitializerFactory;
import cn.ilikes.tools.logs.Loggerfactory;
import cn.ilikes.tools.untils.HBaseUtils;
import cn.ilikes.tools.untils.ObjectUtils;
import cn.ilikes.tools.untils.ObjectUtilsException;
import cn.ilikes.tools.untils.PropertyAccessorHelper;

public abstract class AbClient extends ClientBaseImple implements Client {

	private Logger logger = Loggerfactory.instance(AbClient.class);

	private IndexClient indexClient;

	private DataHander dataHander;

	private JPAHbasePersistenUnitEnv hbasePersistenUnitEnv;

	public AbClient(IndexClient indexClient, DataHander dataHander, JPAHbasePersistenUnitEnv hbasePersistenUnitEnv) {
		super();
		this.indexClient = indexClient;
		this.dataHander = dataHander;
		this.hbasePersistenUnitEnv = hbasePersistenUnitEnv;
	}

	public IndexClient getIndexClient() {
		return indexClient;
	}

	public DataHander getDataHander() {
		return dataHander;
	}

	protected IEntityMetaData findIEntityMetaData(Class<?> clazz) {

		return hbasePersistenUnitEnv.getEntityMetaDataFactory().selectIEntityMetaData(clazz);
	}

	protected JPAHbaseSystemEnv getJPAHbaseSystemEnv() {
		return hbasePersistenUnitEnv.getjPAHbaseSystemEnv();
	}

	@Override
	public boolean isOpen() {
		boolean r = getDataHander().isOpen();
		boolean v = getIndexClient().isOpen();
		return (r && v);
	}

	@Override
	public void flush() {

		getDataHander().flush();
		getIndexClient().flush();
	}

	private void relationJPAProxys(EntityFields entityFields, Result result, Object entity) throws JPAHBaseClientsException {
		JPAField jPAField = entityFields.getjPAField();
		// one to many 
		if (PropertyAccessorHelper.isCollection(entityFields.getField().getType())) {
			if (Loggerfactory.isdebug(logger))
				Loggerfactory.warn(logger, "<>================> this  " + entityFields.getFieldName() + "  Collection  ");
			try {
				Object va = null;
				if (PropertyAccessorHelper.isList(entityFields.getField().getType())) {
					va = new ArrayList<Object>();
				} else if (PropertyAccessorHelper.isList(entityFields.getField().getType())) {
					va = new HashSet<Object>();
				}

				ObjectUtils.setFieldValue(entityFields.getField(), entity, va);
			} catch (ObjectUtilsException e) {
				throw new JPAHBaseClientsException(e);
			}
		} else {
			String columnName = jPAField.getRelation().getColumnName();
			int index = columnName.indexOf(SysConfigs.hbase_column_family_qualifier);
			byte[] family = HBaseUtils.getBytes(HBaseUtils.getfamily(columnName, index));
			byte[] qualifier = HBaseUtils.getBytes(HBaseUtils.getQualifier(columnName, index));
			byte[] value = result.getValue(family, qualifier);
			if (value == null) {
				try {
					ObjectUtils.setFieldValue(entityFields.getField(), entity, value);
				} catch (ObjectUtilsException e) {
					throw new JPAHBaseClientsException(e);
				}
			} else {
				Relation relation = entityFields.getjPAField().getRelation();
				IEntityMetaData relationEntityMetaData = findIEntityMetaData(relation.getTargetEntity());

				LazyInitializerFactory lazyInitializerFactory = getJPAHbaseSystemEnv().getLazyInitializerFactory();

				Object keyId = HBaseUtils.getByteTosObject(value, relationEntityMetaData.getEntityId().getField());

				Object proxy = lazyInitializerFactory.getProxy(entityFields, relationEntityMetaData, keyId, this);
				try {
					ObjectUtils.setFieldValue(entityFields.getField(), entity, proxy);
				} catch (ObjectUtilsException e) {
					throw new JPAHBaseClientsException(e);
				}

			}
			if (Loggerfactory.isdebug(logger))
				Loggerfactory.warn(logger, "<>================> this  " + columnName + "  Relation  " + value);
		}

		//Object proxys = ceateRelationJPAProxys(entityFields, result);
		//ObjectUtils.setFieldValue(entityFields.getField(), object, proxys);

	}

	public Node ResultToObject(IEntityMetaData entityMetaData, Result result) throws JPAHBaseClientsException {
		try {
			Object object = ObjectUtils.instance(entityMetaData.getEntityClazz());

			Field fieldId = entityMetaData.getEntityId().getField();
			//id key   
			ObjectUtils.setFieldValue(fieldId, object, HBaseUtils.getByteTosObject(result.getRow(), fieldId));
			Map<String, EntityFields> entityfields = entityMetaData.getEntityFields();
			for (Entry<String, EntityFields> entry : entityfields.entrySet()) {
				EntityFields entityFields = entry.getValue();
				if (entityFields.getEntityFieldsType().equals(EntityFields.EntityFieldsType.RoreignKey))
					continue;
				if (entityFields.getField().equals(fieldId))
					continue;
				JPAField jPAField = entityFields.getjPAField();
				//这里要处理
				if (jPAField.isRelation()) {
					relationJPAProxys(entityFields, result, object);
				} else {
					String columnName = jPAField.getColumnName();
					int index = columnName.indexOf(SysConfigs.hbase_column_family_qualifier);
					byte[] family = HBaseUtils.getBytes(HBaseUtils.getfamily(columnName, index));
					byte[] qualifier = HBaseUtils.getBytes(HBaseUtils.getQualifier(columnName, index));
					byte[] value = result.getValue(family, qualifier);
					ObjectUtils.setFieldValue(entityFields.getField(), object, HBaseUtils.getByteTosObject(value, entityFields.getField()));
				}
			}
			Node node = Node.createtNode(entityMetaData, object, LifeCycle.managed);
			return node;
		} catch (ObjectUtilsException e) {
			throw new JPAHBaseClientsException(e);
		}
	}
}